package com.syh.jn.scm.infrastructure.repository.impl.supplier.stock;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.infrastructure.repository.AbstractAggregateRepository;
import com.syh.jn.scm.domain.supplier.entity.stock.StockSpill;
import com.syh.jn.scm.domain.supplier.entity.stock.StockSpillItem;
import com.syh.jn.scm.domain.supplier.repository.stock.StockSpillRepository;
import com.syh.jn.scm.dto.supplier.stock.StockSpillItemVo;
import com.syh.jn.scm.dto.supplier.stock.StockSpillVo;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsBrandModel;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsCategoryModel;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsModel;
import com.syh.jn.scm.infrastructure.repository.model.stock.stockSpill.StockSpillItemModel;
import com.syh.jn.scm.infrastructure.repository.model.stock.stockSpill.StockSpillModel;
import com.syh.jn.scm.infrastructure.repository.utils.MybatisTemplate;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import com.syh.jn.scm.infrastructure.wrapper.BaseResolve;
import com.syh.jn.scm.infrastructure.wrapper.ResolveToSQL;
import org.apache.ibatis.jdbc.SQL;
import org.hibernate.Query;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 报溢单管理
 */
@Repository
public class StockSpillRepositoryImpl extends AbstractAggregateRepository<StockSpill, StockSpillModel, Long> implements StockSpillRepository {
  /**
   * 重写add方法
   *
   * @param stockSpill
   * @return
   */
  @Override
  public Long add(StockSpill stockSpill) {
    //保存报溢单基础信息
    StockSpillModel stockSpillModel = new StockSpillModel();
    ExtBeanUtils.copyProperties(stockSpill, stockSpillModel);

    //添加报溢单基础信息成功返回id
    Long spillId = (Long) this.hibernateTemplate.save(stockSpillModel);

    //保存当前报溢单对应的报溢单项
    this.saveSpillItems(spillId, stockSpill.getSpillItems());

    return spillId;
  }

  /**
   * 重写remove方法
   *
   * @param stockSpill
   */
  @Override
  public void remove(StockSpill stockSpill) {
    //删除报溢单基础数据
    super.removeById(stockSpill.getId());
    //删除符合条件的报溢单项
    this.removeItem(stockSpill);
  }

  /**
   * 重写update方法
   *
   * @param stockSpill
   */
  @Override
  public void update(StockSpill stockSpill) {
    //修改报溢单基础数据
    super.update(stockSpill);
    //删除符合条件的报溢单项
    this.removeItem(stockSpill);
    //存储新的报溢单项
    this.saveSpillItems(stockSpill.getId(), stockSpill.getSpillItems());
  }

  /**
   * 重写getById
   *
   * @param id
   * @return
   */
  @Override
  public StockSpill getById(Long id) {
    StockSpill stockSpill = super.getById(id);
    if (stockSpill == null) {
      return stockSpill;
    }
    //查找出报溢单所对应的报溢项
    String hql = "from StockSpillItemModel model where model.spillId = ?";
    List<StockSpillItemModel> itemModelList = (List<StockSpillItemModel>) this.hibernateTemplate.find(hql, id);

    //转换对象并放入报溢单领域对象
    List<StockSpillItem> itemList = new ArrayList<>();
    itemModelList.stream().forEach(itemModel -> {
      StockSpillItem stockSpillItem = new StockSpillItem();
      ExtBeanUtils.copyProperties(itemModel, stockSpillItem);

      itemList.add(stockSpillItem);
    });

    stockSpill.setSpillItems(itemList);
    return stockSpill;
  }

  /**
   * 更新报溢单状态
   *
   * @param overflow
   */
  @Override
  public void updateStatus(StockSpill overflow) {
    super.update(overflow);
  }

  /**
   * 保存当前报溢单对应的报溢单项
   *
   * @param spillId 报溢单id
   * @param items   当前报溢单所对应的报溢单项集合
   */
  private void saveSpillItems(Long spillId, List<StockSpillItem> items) {
    //保存报溢单项
    items.stream().forEach(item -> {
      StockSpillItemModel stockSpillItemModel = new StockSpillItemModel();

      GoodsModel goodsModel = this.hibernateTemplate.get(GoodsModel.class, item.getGoodsId());
      GoodsCategoryModel goodsCategoryModel = new GoodsCategoryModel();
      if (goodsModel.getCategoryId() != null) {
        goodsCategoryModel = this.hibernateTemplate.get(GoodsCategoryModel.class, goodsModel.getCategoryId());
      }
      GoodsBrandModel goodsBrandModel = new GoodsBrandModel();
      if (goodsModel.getGoodsBrandId() != null) {
        goodsBrandModel = this.hibernateTemplate.get(GoodsBrandModel.class, goodsModel.getGoodsBrandId());
      }
      StockSpillModel stockSpillModel = this.hibernateTemplate.get(StockSpillModel.class, spillId);

      ExtBeanUtils.copyProperties(item, stockSpillItemModel);
      stockSpillItemModel.setSpillId(spillId);
      stockSpillItemModel.setBusinessEntityId(stockSpillModel.getBusinessEntityId());
      //在仓储层冗余是为了安全和数据的准确
      stockSpillItemModel.setGoodsName(goodsModel.getName());
      stockSpillItemModel.setConversionRate(goodsModel.getConversionRate());
      stockSpillItemModel.setCode(goodsModel.getCode());
      stockSpillItemModel.setSpecName(goodsModel.getSpecName());
      stockSpillItemModel.setConversionRate(goodsModel.getConversionRate());
      stockSpillItemModel.setUnits(goodsModel.getUnits());
      stockSpillItemModel.setCategoryId(goodsModel.getCategoryId());
      stockSpillItemModel.setCategoryName(goodsCategoryModel.getName());
      stockSpillItemModel.setCategoryCatalogCode(goodsCategoryModel.getCatalogCode());
      stockSpillItemModel.setGoodsBrandId(goodsBrandModel.getId());
      stockSpillItemModel.setGoodsBrandName(goodsBrandModel.getName());
      this.hibernateTemplate.save(stockSpillItemModel);
    });
  }

  /**
   * 删除符合条件的报溢单项
   *
   * @param stockSpill
   */
  private void removeItem(StockSpill stockSpill) {
    //根据lossOrderId查找报溢项
    StringBuffer hql = new StringBuffer();
    hql.append("from StockSpillItemModel model where model.spillId = ?");
    List<StockSpillItemModel> itemModelList = (List<StockSpillItemModel>) this.hibernateTemplate.find(hql.toString(), stockSpill.getId());

    //删除所有符合要求的报溢项
    itemModelList.stream().forEach(spillItem -> {
      this.hibernateTemplate.delete(spillItem);
    });
  }

  /**
   * 根据报损单id获取报损单明细
   * @param id
   * @return
   */
  @Override
  public List<StockSpillItemVo> getItemVosById(Long id) {
    String hql = "from StockSpillItemModel model where model.spillId = ? ";
    List<StockSpillItemModel> modelList = (List<StockSpillItemModel>) this.hibernateTemplate.find(hql, id);
    List<StockSpillItemVo> itemVos = new ArrayList<>();
    if (modelList != null && modelList.size() > 0) {
      for (StockSpillItemModel itemModel : modelList) {
        StockSpillItemVo item = new StockSpillItemVo();
        ExtBeanUtils.copyProperties(itemModel, item);
        itemVos.add(item);
      }
    }
    return itemVos;
  }

  /**
   * 根据服务商id删除采购单
   * @param businessEntityId
   */
  @Override
  public void deleteByBusinessEntityId(Long businessEntityId) {
    String itemHql = "delete from StockSpillItemModel where businessEntityId = :businessEntityId";
    Query itemQuery = this.hibernateTemplate.getSessionFactory().getCurrentSession().createQuery(itemHql);
    itemQuery.setParameter("businessEntityId",businessEntityId);
    itemQuery.executeUpdate();
    String orderHql = "delete from StockSpillModel where businessEntityId = :businessEntityId";
    Query orderQuery = this.hibernateTemplate.getSessionFactory().getCurrentSession().createQuery(orderHql);
    orderQuery.setParameter("businessEntityId",businessEntityId);
    orderQuery.executeUpdate();
  }

  @Override
  protected SQL getViewSql() {
    return new SQL() {{
      SELECT(
              "DISTINCT spill.ID",
              SQLAliasGenerateUtil.aliasGenerate(StockSpillModel.class, "spill", null),
              "storehouse.NAME AS storehouseName,account.NAME AS operatorName"
      );
      FROM("T_STOCK_STOCK_SPILL spill");
      LEFT_OUTER_JOIN("T_BASE_STOREHOUSE storehouse on spill.STOREHOUSE_ID = storehouse.ID");
      LEFT_OUTER_JOIN("T_STOCK_STOCK_SPILL_ITEM item ON item.SPILL_ID = spill.ID");
      LEFT_OUTER_JOIN("T_SYSTEM_ACCOUNT account ON account.ID = spill.OPERATOR_ID");
    }};
  }

  @Override
  public int getCountView(Wrapper wrapper) {
    StringBuffer sqlSb = new StringBuffer();
    String viewSql = this.getViewSql().toString();

    String viewSqlAry[] = viewSql.split("\\s*FROM\\s*");
    sqlSb.append("SELECT COUNT(DISTINCT spill.ID) AS COUNT FROM ");
    for (int i = 1; i <= viewSqlAry.length - 1; i++) {
      if (i > 1) {
        sqlSb.append(" FROM ").append(viewSqlAry[i]);
      } else {
        sqlSb.append(viewSqlAry[i]);
      }
    }
    BaseResolve resolveToSQL = this.getViewWrapperResolve(wrapper);
    sqlSb.append(" WHERE 1=1 ");
    sqlSb.append(resolveToSQL.resolve());

    Map resultM = MybatisTemplate.selectOne(sqlSb.toString());
    return Integer.parseInt(resultM.get("COUNT").toString());
  }

  @Override
  protected Class getViewObject() {
    return StockSpillVo.class;
  }

  protected BaseResolve getViewWrapperResolve(Wrapper wrapper) {
    HashMap<String, String> weMap = new HashMap<>();
    weMap.put("status", "spill.STATUS");
    weMap.put("lossOrderCode", "spill.SPILL_CODE");
    weMap.put("originalOrderCode", "spill.ORIGINAL_ORDER_CODE");
    weMap.put("lossDateTimestamp", "spill.SPILL_DATE_TIMESTAMP");
    weMap.put("lossType", "spill.SPILL_TYPE");
    weMap.put("storehouseId", "spill.STOREHOUSE_ID");
    weMap.put("businessEntityId", "spill.BUSINESS_ENTITY_ID");
    weMap.put("id", "spill.ID");
    weMap.put("goodsId", "item.GOODS_ID");
    weMap.put("goodsName", "item.GOODS_NAME");
    ResolveToSQL parse = new ResolveToSQL(wrapper, (propertyName) -> {
      return weMap.get(propertyName);
    });
    return parse;
  }

  /**
   * 判断报溢项是否存在该商品
   *
   * @param column
   * @param id
   * @return
   */
  @Override
  public boolean stockSpillItemExistsById(String column, Long id) {
    StringBuffer hql = new StringBuffer("SELECT COUNT(*) FROM StockSpillItemModel where ").append(column).append(" = ").append(id);
    this.getLogger().debug(hql.toString());
    Query query = buildQuery(hql);
    return ((Long) query.uniqueResult()).intValue() > 0;
  }

  /**
   * 获取明细对象
   *
   * @param id      明细id
   * @param goodsId 明细商品id
   * @return
   */
  @Override
  public StockSpillItem getItemByIdAndGoodsId(Long id, Long goodsId) {
    String hql = "from StockSpillItemModel model where model.id = ? and model.goodsId = ?";
    List<StockSpillItemModel> modelList = (List<StockSpillItemModel>) this.hibernateTemplate.find(hql, id, goodsId);
    StockSpillItem item = null;
    if (modelList != null && modelList.size() > 0) {
      for (StockSpillItemModel itemModel : modelList) {
        item = new StockSpillItem();
        ExtBeanUtils.copyProperties(itemModel, item);
      }
    }
    return item;
  }
}
